using System;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace SteeringBehaviors
{
    public class BaseObject
    {
        #region PRIVATE MEMBERS

        static uint counter = 0;
        uint id;
        string type;
        Vector3 position;
        Size dimensions;
        float heading;
        float radius;
        float radiusSquared;
        string image;
        Size imageDimensions;
        ColorValue color;

        #endregion

        #region PROPERTIES

        ///<summary>
        /// Obtain this object's ID number
        ///</summary>
        public uint ID
        {
            get { return id; }
            protected set { id = value; }
        }

        /// <summary>
        /// X and Y coordinates of the CENTER of this object in world space
        /// </summary>
        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }

        /// <summary>
        /// Dimensions of this object; used for rendering only.
        /// </summary>
        public Size Dimensions
        {
            get { return dimensions; }
            set { dimensions = value; }
        }

        /// <summary>
        /// Sets the facing (a.k.a rotation) of this object.  Value is in radians.
        /// </summary>
        public float Heading
        {
            get { return heading; }
            set
            {
                heading = value;
                while (heading >= Math.PI)
                    heading -= Convert.ToSingle(Math.PI) * 2f;
                while (heading <= -Math.PI)
                    heading += Convert.ToSingle(Math.PI) * 2f;
            }
        }

        /// <summary>
        /// Radius of this object if treated as a sphere; used for collision checks.
        /// </summary>
        public float Radius
        {
            get { return radius; }
            set
            {
                radius = value;
                if (radius < 0)
                    radius = 0;
                radiusSquared = radius * radius;
            }
        }

        /// <summary>
        /// Radius value squared; useful for collision and distance checks.
        /// </summary>
        public float RadiusSquared
        {
            get { return radiusSquared; }
        }

        /// <summary>
        /// Filename of image used for rendering.
        /// </summary>
        public string Image
        {
            get { return image; }
            set { image = value; }
        }

        /// <summary>
        /// Dimensions of image file used for rendering.
        /// </summary>
        public Size ImageDimensions
        {
            get { return imageDimensions; }
            set { imageDimensions = value; }
        }

        /// <summary>
        /// Color modulation to use for rendering.
        /// </summary>
        public ColorValue DXColor
        {
            get { return color; }
            set { color = value; }
        }

        /// <summary>
        /// Tag used to determine type of object when stored in a collection of a parent type
        /// </summary>
        public string Type
        {
            get { return type; }
            protected set { type = value; }
        }

        #endregion

        #region CONSTRUCTORS

        /// <summary>
        /// Default constructor
        /// </summary>
        public BaseObject()
        {
            Type = "BaseObject";
            Position = new Vector3();
            Dimensions = new Size(16, 16);
            Radius = 8f;
            Image = null;
            ImageDimensions = new Size(16, 16);
            DXColor = new ColorValue(1f, 1f, 1f, 1f);
            id = counter++;
            //TurningSpeed = Convert.ToSingle(Math.PI);
        }

        #endregion

        #region INTERFACE METHODS

        /// <summary>
        /// Obtains an angle value from a given vector.
        /// </summary>
        /// <param name="forward">The vector to obtain the angle of</param>
        /// <returns>angle from x-axis in radians</returns>
        public void SetHeadingFromVector3(Vector3 forward)
        {
            if (forward.X == 0 && forward.Y == 0 && forward.Z == 0)
                return;
            float futureHeading = 0;
            forward.Normalize();
            if (forward.Y < 0)
                futureHeading = Convert.ToSingle(-Math.Acos(forward.X));
            else
                futureHeading = Convert.ToSingle(Math.Acos(forward.X));

            if (Single.IsNaN(heading))
            {
                futureHeading = 0;
                return;
            }
            Heading = futureHeading;
        }


        /// <summary>
        /// Renders this object
        /// </summary>
        /// <param name="sprite">DirectX sprite object to use for rendering</param>
        public virtual void Render(Sprite sprite)
        {
            Rendering.Render(this, sprite);
        }

        /// <summary>
        /// Tests if this object has collided with the parameter.
        /// </summary>
        /// <param name="other">the other object to test for collision</param>
        /// <returns>true if this object and the other object are attempting to occupy the same space</returns>
        public virtual bool Collide(BaseObject other)
        {
            // sphere to sphere collision test
            Vector3 distance = other.Position - Position;
            if (RadiusSquared >= distance.LengthSq())
                return true;
            return false;
        }

        /// <summary>
        /// Obtain a forward vector from this object's heading
        /// </summary>
        /// <returns>Returns a Vector3 representing a unit length "forward" vector</returns>
        public Vector3 GetForward()
        {
            return new Vector3(Convert.ToSingle(Math.Cos(Heading)), Convert.ToSingle(Math.Sin(Heading)), 0.0f);
        }

        #endregion
    }
}
